
namespace FastFood.DataAccess
{
	using System;
	using System.Collections.Generic;
	using System.Data;
	using System.Data.Common;
	using Microsoft.Practices.EnterpriseLibrary.Data;
	using EDOSwit.Entity;
	using FastFood.Business.Entities;

	/// <summary>
	/// Represents the DataAccess of ProductosData.
	/// </summary>
	public class ProductosData : Singleton<ProductosData>
	{
		#region Attributes

		private readonly Database BaseDatos = DatabaseFactory.CreateDatabase();

		#endregion

		#region Methods

		/// <summary>
		/// Selects all records from the Productos table by a foreign key.
		/// </summary>
		public IList<Productos> Listar()
		{
			var entidades = new List<Productos>();
			var comando = BaseDatos.GetStoredProcCommand("SelectAllProductos");

			using (var lector = BaseDatos.ExecuteReader(comando))
			{
				while (lector.Read())
				{
					entidades.Add(new Productos
					{
						productoID = lector.IsDBNull(lector.GetOrdinal("productoID"))? default(short) : lector.GetInt16(lector.GetOrdinal("productoID")),
						nombre = lector.IsDBNull(lector.GetOrdinal("nombre"))? default(string) : lector.GetString(lector.GetOrdinal("nombre")),
						precio = MathExpression.Round(lector.GetDecimal(lector.GetOrdinal("precio"))),
						descripcion = lector.IsDBNull(lector.GetOrdinal("descripcion"))? default(string) : lector.GetString(lector.GetOrdinal("descripcion"))
					});
				}
			}
			comando.Dispose();
			return entidades;
		}

		/// <summary>
		/// Selects all records from the Productos table by a foreign key.
		/// </summary>
		public Productos Obtener(short productoID)
		{
			var productos = default(Productos);

			var comando = BaseDatos.GetStoredProcCommand("SelectProductos");
			BaseDatos.AddInParameter(comando, "productoID", DbType.Int16, productoID);
            using (var lector = BaseDatos.ExecuteReader(comando))
			{
				if (lector.Read())
				{
					productos = new Productos
					{
						productoID = lector.IsDBNull(lector.GetOrdinal("productoID"))? default(short) : lector.GetInt16(lector.GetOrdinal("productoID")),
						nombre = lector.IsDBNull(lector.GetOrdinal("nombre"))? default(string) : lector.GetString(lector.GetOrdinal("nombre")),
                        precio = MathExpression.Round(lector.GetDecimal(lector.GetOrdinal("precio"))),
						descripcion = lector.IsDBNull(lector.GetOrdinal("descripcion"))? default(string) : lector.GetString(lector.GetOrdinal("descripcion"))
					};
				}
            }

            productos.Productos_Insumos = new System.Data.Linq.EntitySet<Productos_Insumos>();
            comando = BaseDatos.GetStoredProcCommand("SelectProductos_InsumosByProductoID");
            BaseDatos.AddInParameter(comando, "productoID", DbType.Int16, productoID);
            using (var lector = BaseDatos.ExecuteReader(comando))
            {
                while (lector.Read())
                {
                    productos.Productos_Insumos.Add(new Productos_Insumos
                    {
                        productoID = lector.IsDBNull(lector.GetOrdinal("productoID")) ? default(short) : lector.GetInt16(lector.GetOrdinal("productoID")),
                        insumoID = lector.IsDBNull(lector.GetOrdinal("insumoID")) ? default(short) : lector.GetInt16(lector.GetOrdinal("insumoID")),
                        cantidad = MathExpression.Round(lector.GetDouble(lector.GetOrdinal("cantidad"))),
                        nombreInsumo = lector.IsDBNull(lector.GetOrdinal("insumo")) ? default(string) : lector.GetString(lector.GetOrdinal("insumo"))
                    });
                }
            }
			comando.Dispose();
			return productos;
		}

		/// <summary>
		/// Saves a record to the Productos table.
		/// </summary>
        private short AgregarBase(Productos productos, DbTransaction transaccion)
		{            
			var comando = BaseDatos.GetStoredProcCommand("InsertProductos");
            BaseDatos.AddOutParameter(comando, "productoID", DbType.Int16, 2);
			BaseDatos.AddInParameter(comando, "nombre", DbType.String, productos.nombre);
			BaseDatos.AddInParameter(comando, "precio", DbType.Currency, MathExpression.Round(productos.precio));
			BaseDatos.AddInParameter(comando, "descripcion", DbType.String, productos.descripcion);

			var resultado = BaseDatos.ExecuteNonQuery(comando, transaccion);
			if (resultado == 0) throw new Exception("Error al Agregar Productos.");

			var valorDevuelto = (short)BaseDatos.GetParameterValue(comando, "productoID");;
			comando.Dispose();
			return valorDevuelto;
		}

		/// <summary>
		/// Updates a record in the Productos table.
		/// </summary>
        public bool ModificarBase(Productos productos, DbTransaction transaccion)
		{
			var comando = BaseDatos.GetStoredProcCommand("UpdateProductos");
			BaseDatos.AddInParameter(comando, "productoID", DbType.Int16, productos.productoID);
			BaseDatos.AddInParameter(comando, "nombre", DbType.String, productos.nombre);
			BaseDatos.AddInParameter(comando, "precio", DbType.Currency, MathExpression.Round(productos.precio));
			BaseDatos.AddInParameter(comando, "descripcion", DbType.String, productos.descripcion);

			var resultado = BaseDatos.ExecuteNonQuery(comando, transaccion);
			if (resultado == 0) throw new Exception("Error al Modificar Productos.");

			comando.Dispose();
			return true;
		}

        /// <summary>
        /// Saves a record to the Productos table.
        /// </summary>
        public short Agregar(Productos productos)
        {
            short productoID;
            using (DbConnection conexion = BaseDatos.CreateConnection())
            {
                conexion.Open();
                DbTransaction transaccion = conexion.BeginTransaction();

                try
                {
                    productoID = this.AgregarBase(productos, transaccion);
                    foreach (Productos_Insumos detalle in productos.Productos_Insumos)
                    {
                        Productos_InsumosData.Instancia.Agregar(productoID, detalle, transaccion);
                    }
                    transaccion.Commit();
                }
                catch (Exception)
                {
                    transaccion.Rollback();
                    throw;
                }
                conexion.Close();
            }
            return productoID;
        }

        /// <summary>
        /// Updates a record in the Productos table.
        /// </summary>
        public bool Modificar(Productos productos)
        {
            using (DbConnection conexion = BaseDatos.CreateConnection())
            {
                conexion.Open();
                DbTransaction transaccion = conexion.BeginTransaction();

                try
                {
                    this.ModificarBase(productos, transaccion);
                    Productos_InsumosData.Instancia.EliminarPorProductoID(productos.productoID, transaccion);
                    foreach (Productos_Insumos detalle in productos.Productos_Insumos)
                    {
                        Productos_InsumosData.Instancia.Agregar(productos.productoID, detalle, transaccion);
                    }
                    transaccion.Commit();
                }
                catch (Exception)
                {
                    transaccion.Rollback();
                    throw;
                }
                conexion.Close();
            }
            return true;
        }

        /// <summary>
        /// Deletes a record from the Productos table by its primary key.
        /// </summary>
        public bool Eliminar(short productoID)
        {
            var comando = BaseDatos.GetStoredProcCommand("DeleteProductos");
            BaseDatos.AddInParameter(comando, "productoID", DbType.Int16, productoID);

            var resultado = BaseDatos.ExecuteNonQuery(comando);
            if (resultado == 0) throw new Exception("Error al Eliminar Productos.");
            comando.Dispose();
            return true;
        }

		#endregion
	}
}
